﻿using Engine;
using Engine.Graphics;
using Game;
using GameEntitySystem;
using System;
using System.Collections.Generic;
using static Game.TerrainContentsGenerator21;

namespace Game
{
    public class Dismemberment : ModLoader
    {
        // 存储每个生物的肢解程度(0-100)
        private Dictionary<Entity, float> dismembermentLevels = new Dictionary<Entity, float>();

        // 缓存生物名称到原始尸体持续时间的映射
        private Dictionary<string, float> creatureCorpseDurations = new Dictionary<string, float>();

        // 粒子系统管理器
        private SubsystemParticles m_subsystemParticles;

        // 肢解部位定义（按显示顺序）
        private static readonly string[] DismembermentParts = {
        "头", "臂", "腿", "躯干"
        };
        private Random m_random = new Random();

        public override void __ModInitialize()
        {
            ModsManager.RegisterHook("OnMinerHit", this);
            ModsManager.RegisterHook("OnProjectLoaded", this);
        }

        public override void OnProjectLoaded(Project project)
        {
            // 获取粒子系统引用
            m_subsystemParticles = project.FindSubsystem<SubsystemParticles>(throwOnError: true);
        }

        public override void OnMinerHit(ComponentMiner miner, ComponentBody componentBody, Vector3 hitPoint, Vector3 hitDirection, ref float attackPower, ref float playerProbability, ref float creatureProbability, out bool Hitted)
        {
            Hitted = false;

            if (componentBody?.Entity == null) return;

            var creatureComponent = componentBody.Entity.FindComponent<ComponentCreature>();
            var healthComponent = componentBody.Entity.FindComponent<ComponentHealth>();
            var corpseComponent = componentBody.Entity.FindComponent<ComponentHealth>();

            if (creatureComponent == null || healthComponent == null) return;

            Entity creatureEntity = componentBody.Entity;
            string creatureName = GetCreatureName(creatureEntity);

            // 缓存原始尸体持续时间
            CacheCorpseDuration(creatureName, corpseComponent);

            // 初始化肢解程度（如果尚未记录）
            if (!dismembermentLevels.TryGetValue(creatureEntity, out float dismembermentLevel))
            {
                dismembermentLevel = 100f;
                dismembermentLevels[creatureEntity] = dismembermentLevel;
            }

            // 只有当生物生命值小于等于0时才处理肢解逻辑
            if (healthComponent.Health <= 0)
            {
                // 第一次死亡时设置肢解程度为100%
                if (dismembermentLevels[creatureEntity] == 100f)
                {
                    dismembermentLevel = 100f;
                }

                // 每次攻击尸体时按固定值减少肢解度(第一次减到80%，第二次减到60%，直到0)
                if (dismembermentLevel > 80f)
                    dismembermentLevel = 80f;
                else if (dismembermentLevel > 60f)
                    dismembermentLevel = 60f;
                else if (dismembermentLevel > 40f)
                    dismembermentLevel = 40f;
                else if (dismembermentLevel > 20f)
                    dismembermentLevel = 20f;
                else if (dismembermentLevel > 0f)
                    dismembermentLevel = 0f;

                dismembermentLevels[creatureEntity] = dismembermentLevel;

                HandleCreatureDeath(creatureEntity, creatureName, hitPoint, dismembermentLevel);

                // 显示当前肢解信息
                DisplayDismembermentInfo(creatureEntity, creatureName, dismembermentLevel, hitPoint, true);
                return;
            }
        }

        // 缓存生物原始尸体持续时间
        private void CacheCorpseDuration(string creatureName, ComponentHealth corpseComponent)
        {
            if (corpseComponent != null && !creatureCorpseDurations.ContainsKey(creatureName))
            {
                creatureCorpseDurations[creatureName] = corpseComponent.CorpseDuration;
            }
        }

        // 处理生物死亡
        private void HandleCreatureDeath(Entity creatureEntity, string creatureName, Vector3 hitPoint, float dismembermentLevel)
        {
            var corpseComponent = creatureEntity.FindComponent<ComponentHealth>();
            if (dismembermentLevel > 0f)
            {
                corpseComponent.CorpseDuration = 0;
            }

            // 根据肢解程度触发不同的肢解效果
            if (dismembermentLevel <= 80f && dismembermentLevel > 60f)
            {
                // 第一次显示头部
                TriggerSpecificDismembermentEffect(hitPoint, 0, 1); // 头部，严重程度1
            }
            else if (dismembermentLevel <= 60f && dismembermentLevel > 40f)
            {
                // 第二次显示臂部
                TriggerSpecificDismembermentEffect(hitPoint, 1, 2); // 臂部，严重程度2
            }
            else if (dismembermentLevel <= 40f && dismembermentLevel > 20f)
            {
                // 第三次显示腿部
                TriggerSpecificDismembermentEffect(hitPoint, 2, 3); // 腿部，严重程度3
            }
            else if (dismembermentLevel <= 20f && dismembermentLevel > 0f)
            {
                // 第四次显示躯干
                TriggerSpecificDismembermentEffect(hitPoint, 3, 3); // 躯干，严重程度3
            }
            else if (dismembermentLevel <= 0f)
            {
                // 第五次显示完整身体
                TriggerCompleteDismemberment(hitPoint);
                dismembermentLevels[creatureEntity] = 0f;
                creatureEntity.Project.RemoveEntity(creatureEntity, true);
                dismembermentLevels.Remove(creatureEntity);
            }
        }
        // 触发特定部位的肢解效果
        private void TriggerSpecificDismembermentEffect(Vector3 position, int partIndex, int severity)
        {
            if (m_subsystemParticles == null) return;

            string[] parts = new string[severity];

            // 根据索引显示特定部位
            for (int i = 0; i < severity; i++)
            {
                parts[i] = DismembermentParts[partIndex];
            }

            var terrain = m_subsystemParticles.Project.FindSubsystem<SubsystemTerrain>();
            m_subsystemParticles.AddParticleSystem(new DisjointInfoParticleSystem(position, parts, terrain));
        }

        // 获取生物名称
        private string GetCreatureName(Entity entity)
        {
            var nameComponent = entity.FindComponent<ComponentName>();
            if (nameComponent != null && !string.IsNullOrEmpty(nameComponent.Name))
            {
                return nameComponent.Name;
            }
            return entity.GetType().Name;
        }

        // 显示肢解信息（结合粒子效果）
        private void DisplayDismembermentInfo(Entity entity, string creatureName, float dismembermentLevel, Vector3 hitPoint, bool isDeath = false)
        {
            string displayText = $"{creatureName}[肢解:{dismembermentLevel:F0}%]";
            Vector3 displayPosition = hitPoint + new Vector3(0, 1f, 0);

            // 添加文字粒子效果
            if (m_subsystemParticles != null)
            {
                Color textColor = isDeath ? Color.Red : GetColorByLevel(dismembermentLevel);
                m_subsystemParticles.AddParticleSystem(new HitValueParticleSystem(
                    displayPosition,
                    new Vector3(0, 0.8f, 0),
                    textColor,
                    displayText
                ));
            }
        }

        // 根据肢解程度获取颜色
        private Color GetColorByLevel(float level)
        {
            if (level > 75) return Color.Green;
            if (level > 50) return Color.Yellow;
            if (level > 25) return Color.Orange;
            return Color.Red;
        }

        // 触发肢解效果
        private void TriggerDismembermentEffect(Vector3 position, int severity)
        {
            if (m_subsystemParticles == null) return;

            int particleCount = 3 + (severity * 2);
            string[] parts = new string[particleCount];

            for (int i = 0; i < particleCount; i++)
            {
                parts[i] = DismembermentParts[m_random.Int(DismembermentParts.Length)];
            }

            var terrain = m_subsystemParticles.Project.FindSubsystem<SubsystemTerrain>();
            m_subsystemParticles.AddParticleSystem(new DisjointInfoParticleSystem(position, parts, terrain));
        }

        private void TriggerCompleteDismemberment(Vector3 position)
        {
            if (m_subsystemParticles == null) return;

            var terrain = m_subsystemParticles.Project.FindSubsystem<SubsystemTerrain>();
            m_subsystemParticles.AddParticleSystem(new DisjointInfoParticleSystem(position, DismembermentParts, terrain));
        }
    }

    public class DisjointInfoParticleSystem : ParticleSystem<DisjointInfoParticleSystem.Particle>
    {
        public class Particle : Game.Particle
        {
            public float TimeToLive;
            public float InitialTimeToLive;
            public Vector3 Velocity;
            public string PartName;
            public float Size;
            public float InitialSize;
            public float Rotation;
            public float RotationSpeed;
            public Color OriginalColor;
            public float BounceFactor = 0.3f;
            public float HighDampingFactor;
            public bool NoGravity;
        }

        private Vector3 m_position;
        private Random m_random = new Random();
        private SubsystemTerrain m_subsystemTerrain;
        private float m_damping = 0.96f;
        private PrimitivesRenderer3D m_primitivesRenderer;

        public DisjointInfoParticleSystem(Vector3 position, string[] partNames, SubsystemTerrain terrain)
            : base(partNames.Length * 2)
        {
            m_position = position;
            m_subsystemTerrain = terrain;
            m_primitivesRenderer = terrain.Project.FindSubsystem<SubsystemParticles>(throwOnError: true).PrimitivesRenderer;
            InitializeParticles(partNames);
        }

        private void InitializeParticles(string[] partNames)
        {
            for (int i = 0; i < base.Particles.Length; i++)
            {
                Particle particle = base.Particles[i];
                string partName = partNames[i % partNames.Length];

                particle.IsActive = true;
                particle.TimeToLive = m_random.Float(1.5f, 3f);
                particle.InitialTimeToLive = particle.TimeToLive;
                particle.PartName = partName;
                particle.InitialSize = m_random.Float(0.2f, 0.4f);
                particle.Size = particle.InitialSize;
                particle.Rotation = m_random.Float(0, MathF.PI * 2);
                particle.RotationSpeed = m_random.Float(-2f, 2f);
                particle.BillboardingMode = ParticleBillboardingMode.Camera;

                // 三维扩散速度
                float angleXZ = m_random.Float(0, MathF.PI * 2);
                float angleY = m_random.Float(-MathF.PI / 6, MathF.PI / 3);
                float speed = m_random.Float(0.8f, 1.5f);
                particle.Velocity = new Vector3(
                    MathF.Cos(angleXZ) * MathF.Cos(angleY) * speed,
                    MathF.Sin(angleY) * speed + m_random.Float(1f, 2f),
                    MathF.Sin(angleXZ) * MathF.Cos(angleY) * speed
                );

                particle.OriginalColor = GetPartColor(partName);
                particle.FlipX = m_random.Bool();
                particle.FlipY = m_random.Bool();
            }
        }

        private Color GetPartColor(string partName)
        {
            int hash = partName.GetHashCode() % 4;
            switch (hash)
            {
                case 0: return new Color(210, 50, 50, 200);    // 红色系
                case 1: return new Color(180, 40, 40, 200);    // 暗红色
                case 2: return new Color(230, 70, 70, 200);    // 亮红色
                default: return new Color(150, 30, 30, 200);   // 深红色
            }
        }

        public override bool Simulate(float dt)
        {
            dt = Math.Clamp(dt, 0f, 0.1f);
            bool hasActive = false;
            float dampingFactor = MathF.Pow(m_damping, dt);

            foreach (var particle in Particles)
            {
                if (particle.IsActive)
                {
                    hasActive = true;
                    particle.TimeToLive -= dt;
                    float lifeRatio = particle.TimeToLive / particle.InitialTimeToLive;

                    // 更新位置和速度
                    particle.Position += particle.Velocity * dt;
                    if (!particle.NoGravity)
                        particle.Velocity.Y -= 9.81f * dt;
                    particle.Velocity *= dampingFactor;

                    // 更新旋转
                    particle.Rotation += particle.RotationSpeed * dt;

                    // 更新大小
                    particle.Size = particle.InitialSize * MathUtils.Saturate(lifeRatio * 1.2f);

                    // 更新颜色
                    particle.Color = particle.OriginalColor * MathUtils.Saturate(lifeRatio * 1.5f);
                    particle.Color.A = (byte)(particle.Color.A * lifeRatio);

                    // 地形碰撞检测
                    CheckTerrainCollision(particle, dt);

                    // 生命周期结束判断
                    if (particle.TimeToLive <= 0 || particle.Size <= 0.05f)
                        particle.IsActive = false;
                }
            }

            return !hasActive;
        }

        private void CheckTerrainCollision(Particle particle, float dt)
        {
            if (m_subsystemTerrain == null) return;

            Vector3 start = particle.Position;
            Vector3 end = particle.Position + particle.Velocity * dt;
            // 碰撞检测委托：排除非碰撞块和树叶块
            var raycast = m_subsystemTerrain.Raycast(
                start, end,
                useInteractionBoxes: false,
                skipAirBlocks: true,
                (value, distance) => {
                    Block block = BlocksManager.Blocks[Terrain.ExtractContents(value)];
                    return block.IsCollidable && !(block is LeavesBlock);
                }
            );

            if (raycast.HasValue)
            {
                particle.Position = raycast.Value.HitPoint(0.01f);
                Plane plane = raycast.Value.CellFace.CalculatePlane();

                if (plane.Normal.X != 0f)
                {
                    particle.Velocity *= new Vector3(-particle.BounceFactor, particle.BounceFactor, particle.BounceFactor);
                }
                if (plane.Normal.Y != 0f)
                {
                    particle.Velocity *= new Vector3(particle.BounceFactor, -particle.BounceFactor, particle.BounceFactor);
                }
                if (plane.Normal.Z != 0f)
                {
                    particle.Velocity *= new Vector3(particle.BounceFactor, particle.BounceFactor, -particle.BounceFactor);
                }

                particle.RotationSpeed += m_random.Float(-1f, 1f);
                particle.HighDampingFactor = m_random.Float(0.5f, 1f);

                if (raycast.Value.CellFace.Face >= 4)
                    particle.NoGravity = true;
            }
        }

        public override void Draw(Camera camera)
        {
            if (m_primitivesRenderer == null) return;

            Matrix view = Matrix.CreateLookAt(
                camera.ViewPosition,
                camera.ViewPosition + camera.ViewDirection,
                Vector3.UnitY
            );
            Vector3 right = view.Right;
            Vector3 up = view.Up;

            foreach (var particle in Particles)
            {
                if (particle.IsActive)
                {
                    float size = particle.Size;
                    Color color = particle.Color;
                    float rotation = particle.Rotation;

                    Vector3[] vertices = CalculateRotatedVertices(particle.Position, right, up, size, rotation);

                    m_primitivesRenderer.FlatBatch(0, DepthStencilState.DepthRead, null, BlendState.AlphaBlend)
                        .QueueQuad(vertices[0], vertices[1], vertices[2], vertices[3], color);

                    DrawText(particle.Position + up * size, particle.PartName, color, size * 5f, camera);
                }
            }
        }

        private Vector3[] CalculateRotatedVertices(Vector3 position, Vector3 right, Vector3 up, float size, float rotation)
        {
            Matrix rotationMatrix = Matrix.CreateRotationZ(rotation);

            Vector3 baseRight = right * size;
            Vector3 baseUp = up * size;

            Vector3 rotatedRight = Vector3.TransformNormal(baseRight, rotationMatrix);
            Vector3 rotatedUp = Vector3.TransformNormal(baseUp, rotationMatrix);

            return new[] {
                position - rotatedRight - rotatedUp,
                position + rotatedRight - rotatedUp,
                position + rotatedRight + rotatedUp,
                position - rotatedRight + rotatedUp
            };
        }

        private void DrawText(Vector3 position, string text, Color color, float size, Camera camera)
        {
            if (string.IsNullOrEmpty(text)) return;

            var textBatch = m_primitivesRenderer.FontBatch(LabelWidget.BitmapFont, 0, DepthStencilState.None);
            Vector3 viewDirection = camera.ViewDirection;
            Vector3 right = Vector3.Normalize(Vector3.Cross(viewDirection, Vector3.UnitY));
            Vector3 up = -Vector3.Normalize(Vector3.Cross(right, viewDirection));

            textBatch.QueueText(
                text,
                position,
                right * size,
                up * size,
                color,
                TextAnchor.HorizontalCenter | TextAnchor.VerticalCenter,
                Vector2.Zero
            );
        }
    }
}